#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#ifdef WIN32
#include "windows.h"
#else
#include <sys/time.h>
#include <time.h>
#endif
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "math.h"
#include "assert.h"

#include "List.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"
#include "Ufeatureterm.h"
#include "AUfeatureterm.h"
#include "FT_refinement.h"
#include "FT_generalization.h"

#include "SpecialTerm.h"
#include "ST_floatInterval.h"

#ifndef WIN32
struct timeval init_tick_count_value;

void setupTickCount()
{
	gettimeofday(&init_tick_count_value, NULL);
}

long GetTickCount()
{
	struct timeval now;
	gettimeofday(&now, NULL);
	struct timeval diff;
	diff.tv_sec = now.tv_sec - init_tick_count_value.tv_sec;
	diff.tv_usec = now.tv_usec - init_tick_count_value.tv_usec;
	if (diff.tv_usec < 0)
	{
		diff.tv_sec--;
		diff.tv_usec+=1000000;
	}
	return diff.tv_sec*1000 + diff.tv_usec/1000;
}
#endif



int main(void)
{
	int t_start,t_last,t_end;

#ifndef WIN32
	setupTickCount();
#endif

	Ontology *o=new Ontology();
	FTKBase *domain_model=new FTKBase(o),*case_base=new FTKBase(o);

	domain_model->create_boolean_objects(o);
	case_base->uses(domain_model);

	printf("Stats 0: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());

	domain_model->ImportNOOS("../NOOS/artificial-ontology.noos",o);
	domain_model->ImportNOOS("../NOOS/artificial-dm.noos",o);
	case_base->ImportNOOS("../NOOS/artificial-512.noos",o);

	ST_floatInterval::createSort(o);

	printf("Stats 1: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());

	printf("There are %i + %i undefined terms.\n",
			domain_model->get_n_undefined_terms(),
			case_base->get_n_undefined_terms());
	domain_model->print_undefined_terms();
	case_base->print_undefined_terms();

	t_last=t_start=GetTickCount();
	{
		// SpecialTerms bsic tests, read from string, print to string, subsumption (retrieval), specialization and generalization:
		if (true) {
			FeatureTerm *ft;
			List<FeatureTerm> *objects;
			char *s;
			// Read from string:
			FeatureTerm *base=FeatureTerm::fromStringNOOS(	"(define (artificial-data) "
															"  (y (define (float-interval) (min 0.25) (max 0.275))) "
															")" ,case_base,o); 
			List<FeatureTerm> *l;

			// Print to string:
			s=base->toStringNOOS(domain_model);
			printf("Base:\n%s\n",s);
			delete []s;

			// subsumption:
			objects=case_base->RetrieveFT(base);
			printf("%i objects retrieved\n",objects->Length());
			objects->Rewind();
			while(objects->Iterate(ft)) {
				s=ft->toStringNOOS();
				printf("%s\n",s);
				delete []s;
			} // while  
			printf("\n");
			
//			l=DSpecialization(base,objects,o,domain_model,10,0,true,true,true,true,true);
			l=DSpecialization_b(base,objects,o,domain_model,0,true,true,true,true,true);
			printf("%i efinements:\n",l->Length());
			l->Rewind();
			while(l->Iterate(ft)) {
				s=ft->toStringNOOS();
				printf("%s\n",s);
				delete []s;
			} // while  
			delete l;
			printf("\n");

			l=DGeneralization(base,o,domain_model);
			printf("%i Generalizations:\n",l->Length());
			l->Rewind();
			while(l->Iterate(ft)) {
				s=ft->toStringNOOS();
				printf("%s\n",s);
				delete []s;
			} // while  
			delete l;
			printf("\n");

			objects->ExtractAll();
			delete objects;
			delete base;

		} // if
	
		// Unification test:
		if (true) {
			FeatureTerm *f1;
			FeatureTerm *f2;
			FeatureTerm *f;
			List<FeatureTerm> *unifications;

			// Example 6: (nested, double variable equality, 4 possible unifications)
			f1=FeatureTerm::fromStringNOOS("(define (artificial-data) "
										   "  (y 3.5) "
										   ")",case_base,o);
			f2=FeatureTerm::fromStringNOOS("(define (artificial-data) "
										   "  (y (define (float-interval) (min 0.25))) "
										   ")",case_base,o);

			unifications=unification(f1,f2,o,domain_model);
			if (unifications!=0 && !unifications->EmptyP()) {
				printf("Unification successful!\n");
				printf("%i unifications:\n",unifications->Length());
				unifications->Rewind();
				while(unifications->Iterate(f)) {
					char *s;
					s=f->toStringNOOS(domain_model);
					printf("%s\n",s);
					delete []s;
				} /* while */ 
			} else {
				printf("Unification failed!\n");
			} /* if */ 

			delete f1;
			delete f2;
			if (unifications!=0) delete unifications;
		} // if 

		t_end=GetTickCount();
		printf("Time taken: %i (total %i)\n",t_end-t_last,t_end-t_start);
		t_last=t_end;

		printf("Stats 2: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());


		/* Specialization tests: */ 
		if (true) {
			FeatureTerm *base,*ft;
			List<FeatureTerm> *l;
			List<FeatureTerm> *objects=new List<FeatureTerm>;
			List<Path> sl;
			Symbol *sym;
			char *s;

			base=FeatureTerm::fromStringNOOS(
											"(define (artificial-data) "
											"  (x (define (float))) "
											"  (y (define (float-interval) (min 0.25) (max 0.9))) "
											")",case_base,o);

			printf("\n\nSpecialization tests:\n");
			s=base->toStringNOOS(domain_model);
			printf("BASE OBJECT:\n%s\n",s);
			delete []s;

			{
				List<FeatureTerm> *nodes,*parentsl;
				List< List<Path> > *paths;
				List< List<Sort> > *sorts;
				List< List<FeatureTerm> > *parents;

				FeatureTerm *node,*parent;
				List<Path> *pl;
				Path *p;
				Symbol *s;
				List<Sort> *sl;
				Sort *sort;


				base->nodesAllPaths(&nodes,&paths);

				printf("ALL PATHS:\n");
				nodes->Rewind();
				paths->Rewind();
				while(nodes->Iterate(node) &&
					  paths->Iterate(pl)) {
					printf("node: %p\npaths:\n",(node==0 ? 0:node->get_content()));
					pl->Rewind();
					while(pl->Iterate(p)) {
						p->Rewind();
						printf("  ");
						while(p->Iterate(s)) printf("%s ",s->get());
						printf("\n");
					} // while  
				} // while  

				while(!nodes->EmptyP()) nodes->ExtractIni();
				delete nodes;
				delete paths;



				base->nodesAllPathsSorts(&nodes,&paths,&sorts,o);

				printf("ALL PATHS / SORTS:\n");
				nodes->Rewind();
				paths->Rewind();
				sorts->Rewind();
				while(nodes->Iterate(node) &&
					  paths->Iterate(pl) &&
					  sorts->Iterate(sl)) {
					printf("node: %p\npaths:\n",(node==0 ? 0:node->get_content()));
					pl->Rewind();
					sl->Rewind();
					while(pl->Iterate(p) &&
						  sl->Iterate(sort)) {
						p->Rewind();
						printf("  ");
						while(p->Iterate(s)) printf("%s ",s->get());
						printf(" (sort: %s)\n",sort->get());
					} // while  
				} // while  

				while(!nodes->EmptyP()) nodes->ExtractIni();
				delete nodes;
				delete paths;
				while(!sorts->EmptyP()) {
					sl=sorts->ExtractIni();
					while(!sl->EmptyP()) sl->ExtractIni();
					delete sl;
				} // while  
				delete sorts;


				base->nodesAllPathsSortsParents(&nodes,&paths,&sorts,&parents,o);

				printf("ALL PATHS / SORTS / PARENTS:\n");
				nodes->Rewind();
				paths->Rewind();
				sorts->Rewind();
				parents->Rewind();
				while(nodes->Iterate(node) &&
					  paths->Iterate(pl) &&
					  sorts->Iterate(sl) &&
					  parents->Iterate(parentsl)) {
					printf("node: %p\npaths:\n",(node==0 ? 0:node->get_content()));
					pl->Rewind();
					sl->Rewind();
					parentsl->Rewind();
					while(pl->Iterate(p) &&
						  sl->Iterate(sort) &&
						  parentsl->Iterate(parent)) {
						p->Rewind();
						printf("  ");
						while(p->Iterate(s)) printf("%s ",s->get());
						printf(" (sort: %s, parent: %p)\n",sort->get(),(parent==0 ? 0:parent->get_content()));
					} // while  
				} // while  

				while(!nodes->EmptyP()) nodes->ExtractIni();
				delete nodes;
				delete paths;
				while(!sorts->EmptyP()) {
					sl=sorts->ExtractIni();
					while(!sl->EmptyP()) sl->ExtractIni();
					delete sl;
				} // while  
				delete sorts;
				delete parents;

			}


			sym=new Symbol("ad-0");
			l=case_base->SearchFT(sym);
			delete sym;
			while(!l->EmptyP()) {
				ft=l->ExtractIni();
				objects->Add(new FeatureTerm(ft));
			} // while  
			delete l;

			sym=new Symbol("ad-1");
			l=case_base->SearchFT(sym);
			delete sym;
			while(!l->EmptyP()) {
				ft=l->ExtractIni();
				objects->Add(new FeatureTerm(ft));
			} // while  
			delete l;

			objects->operator [](0)->set_paths(&sl);

			l=DSpecializationL2(base,objects,&sl,o,10,domain_model);

			printf("%i REFINEMENTS:\n",l->Length());
			l->Rewind();
			while(l->Iterate(ft)) {
				s=ft->toStringNOOS();
				printf("%s\n",s);
				delete []s;
			} // while  

			delete base;
			delete objects;
			delete l;
		
		} // if 

		t_end=GetTickCount();
		printf("Time taken: %i (total %i)\n",t_end-t_last,t_end-t_start);
		t_last=t_end;

		printf("Stats 2: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());


		/* Antiunification tests: */ 
		if (true) {

			FeatureTerm *f;
			char *s;
			List<FeatureTerm> *objects=new List<FeatureTerm>;
			List<FeatureTerm> antiunifications;
//			List<FeatureTerm> antiunifications2;
			List<int> steps2;
//			int *step;
			int t1_start,t1_end;
//			int t2_start,t2_end;

			{
				char *names[]={"ad-0","ad-1","ad-2","ad-3","ad-4"};
//				char *names[]={"r1","r2","r3"};
				List<FeatureTerm> *l;
				FeatureTerm *ft;
				Symbol *sym;
				int i;

				for(i=0;i<5;i++) {
//				for(i=0;i<3;i++) {
					sym=new Symbol(names[i]);
					l=case_base->SearchFT(sym);			
					delete sym;
					while(!l->EmptyP()) {
						ft=l->ExtractIni();
						objects->Add(new FeatureTerm(ft));
					} // while  
					delete l;
				} /* for */ 
			}

			printf("\n\nAntiunification test:\n");			
/*
			objects->Rewind();
			while(objects->Iterate(f)) {
				s=f->toStringNOOS();
				printf("%s\n",s);
				delete []s;
			} // while   
*/
			t1_start=GetTickCount();
//			antiunification(&antiunifications,objects,SPECIALIZATION_LANGUAGE_L2,0,o,domain_model,true,AU_VERSION_COMPLETE);
//			antiunification(&antiunifications,objects,SPECIALIZATION_LANGUAGE_L2,0,o,domain_model,true,AU_VERSION_STANDARD);
			antiunification(&antiunifications,objects,SPECIALIZATION_LANGUAGE_L2,0,o,domain_model,true,AU_VERSION_FAST);
			t1_end=GetTickCount();

			printf("There are %i possible antiunifications (no steps), time: %i.\n",antiunifications.Length(),t1_end-t1_start);
			antiunifications.Rewind();
			while(antiunifications.Iterate(f)) {
				s=f->toStringNOOS(case_base);
				printf("%s\n",s);
				delete []s;
			} // while 

			printf("Check for result correctness:\n");
			{
				List<FeatureTerm> l;
				FeatureTerm *f2;
				int i,j;

				antiunifications.Rewind();
				l.Instance(antiunifications);
				l.Rewind();
				i=0;
				while(antiunifications.Iterate(f)) {
					l.Rewind();
					j=0;
					while(l.Iterate(f2)) {
						if (f->subsumes(f2)) {
							printf("%i subsumes %i\n",i,j);
						} else {
							printf("%i does not subsume %i\n",i,j);
						} // if  
						if (f2->subsumes(f)) {
							printf("%i subsumes %i\n",j,i);
						} else {
							printf("%i does not subsume %i\n",j,i);
						} // if  
						j++;
					} // while  
					i++;
				} // while  
			}

			delete objects;

		} /* antiunification test */ 


		t_end=GetTickCount();
		printf("Time taken: %i (total %i)\n",t_end-t_last,t_end-t_start);
		t_last=t_end;


		printf("Stats 2: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());


		/* Generalization test: */ 
		if (true) {
			FeatureTerm *f,*base;
			char *s;
			List<FeatureTerm> *objects=new List<FeatureTerm>;
			List<FeatureTerm> *generalizations;
			base = FeatureTerm::fromStringNOOS(
												"(define (artificial-data) "
												"  (x (define (float))) "
												"  (y (define (float-interval) (min 0.25) (max 0.9))) "
												")",case_base,o);
			objects->Add(base);

			generalizations=DGeneralization(base,o,domain_model);

			printf("N∫ of generalizations: %i\n",generalizations->Length());
			while(!generalizations->EmptyP()) {
				f=generalizations->ExtractIni();
				s=f->toStringNOOS(domain_model);
				printf("%s\n",s);
				delete []s;
				delete f;
			} // while  
			delete generalizations;
/*
			{
				List<FeatureTerm> result;
				List<int> result_step;
				int *step;

				printf("\n\nComplete generalization:\n");
				Generalize(base,0,&result,&result_step,o,domain_model,true);

				printf("Result: %i\n",result.Length());
				while(!result.EmptyP()) {
					f=result.ExtractIni();
					step=result_step.ExtractIni();
					s=f->toStringNOOS(domain_model);
					printf("STEPS: %i\n%s\n\n",*step,s);
					delete []s;
					delete f;
				} // while  
			}
*/			
			delete objects;

		} /* if */  


		t_end=GetTickCount();
		printf("Time taken: %i (total %i)\n",t_end-t_last,t_end-t_start);
		t_last=t_end;

		printf("Stats 2: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());
	}

	delete case_base;
	delete domain_model;

	printf("Stats 3: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());

	delete o;

	printf("Stats 4: %i %i\n",Symbol::stats_nSymbols(),Symbol::stats_nSymbolReferences());
	Symbol::stats_printSymbolStats();

	Symbol::reset();

	return 0;
} /* main */ 



